﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
using System.Xml;

namespace SpriteAnimator.Classes
{
    /// <summary>
    /// Représente un projet de type zone de texture
    /// </summary>
    public class Textures: IDisposable, ICloneable
    {
        #region Constructeurs et destructeur

        /// <summary>
        /// Constructeur vide  de NoobTexture2DDef
        /// </summary>
        public Textures()
        {
            // *** Initialisation ***

            this.Texture = null;
            this.BackColor = Color.CornflowerBlue;
            this.Zones = new Dictionary<string, Rectangle>();
        }

        /// <summary>
        /// Libère les ressources
        /// </summary>
        public void Dispose()
        {
            this.Zones.Clear();

            if ( this.Texture != null )
            {
                this.Texture.Dispose();
                this.Texture = null;
            }
        }

        #endregion

        #region Fonctions publiques

        /// <summary>
        /// Charge la définition du projet zone
        /// </summary>
        /// <param name="p_sPath">Fichier de chargement</param>
        public void Load(string p_sPath)
        {
            XmlDocument oXml = new XmlDocument();

            // *** Chargement nom ***

            this.Name = Path.GetFileNameWithoutExtension(p_sPath);

            // *** Chargement du XML ***

            oXml.Load(p_sPath);

            // *** Récupération des informations ***

            if ( oXml["definition"].Attributes["backcolor"] != null && !string.IsNullOrEmpty(oXml["definition"].Attributes["backcolor"].Value) )
                this.BackColor = Color.FromArgb(int.Parse(oXml["definition"].Attributes["backcolor"].Value));

            // *** Ajout des frames ***

            this.Zones.Clear();

            foreach ( XmlNode oNode in oXml["definition"].ChildNodes )
                this.Zones.Add(oNode.Attributes["id"].Value, new Rectangle(int.Parse(oNode.Attributes["x"].Value), int.Parse(oNode.Attributes["y"].Value), int.Parse(oNode.Attributes["width"].Value), int.Parse(oNode.Attributes["height"].Value)));

            // *** Chargement texture ***

            using ( FileStream oStream = new FileStream(Path.GetDirectoryName(p_sPath) + Path.GetFileNameWithoutExtension(p_sPath) + ".png", FileMode.Open) )
            {
                this.Texture = Image.FromStream(oStream);
            }

            // *** Sauvegarde du chemin ***

            this.FilePath = p_sPath;
        }

        /// <summary>
        /// Enregistre le projet sur le disque
        /// </summary>
        /// <param name="p_sPath">Chemin ou stocker</param>
        /// <param name="p_sFileNoExt">Nom du fichier sans l'extension</param>
        public void Save(string p_sPath, string p_sFileNoExt)
        {
            StringBuilder oXml = new StringBuilder();

            // *** Vérification path ***

            if ( p_sPath[p_sPath.Length - 1] != '\\' )
                p_sPath += "\\";

            // *** Création du XML ***

            oXml.Append("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n");
            oXml.Append("<definition backcolor=\"" + this.BackColor.ToArgb() + "\">\n");

            // *** Dump des frames ***

            foreach ( KeyValuePair<string, Rectangle> oItem in this.Zones )
                oXml.Append("\t<zone id=\"" + oItem.Key + "\" x=\"" + oItem.Value.X.ToString() + "\" y=\"" + oItem.Value.Y.ToString() + "\" width=\"" + oItem.Value.Width.ToString() + "\" height=\"" + oItem.Value.Height.ToString() + "\" />\n");

            // *** Footer ***

            oXml.Append("</definition>");

            // *** Sauvegarde du fichier n2d ***

            File.WriteAllText(p_sPath + p_sFileNoExt + ".n2t", oXml.ToString(), Encoding.UTF8);

            // *** Sauvegarde de l'image ***

            this.Texture.Save(p_sPath + p_sFileNoExt + ".png", ImageFormat.Png);

            // *** Sauvegarde du chemin ***

            this.Name = p_sFileNoExt;
            this.FilePath = p_sPath + p_sFileNoExt + ".n2t";
        }

        #endregion

        #region Indexer

        /// <summary>
        /// Retourne le rectangle de positionnement dans la texteure pour un alias donné
        /// </summary>
        /// <param name="p_sName">Nom de l'alias</param>
        /// <returns>Rectangle de définition</returns>
        public Rectangle this[string p_sName]
        {
            get
            {
                return (this.Zones[p_sName]);
            }
        }

        /// <summary>
        /// Affecte ou retourne la couleur de fond
        /// </summary>
        public Color BackColor
        {
            get;
            set;
        }

        /// <summary>
        /// Affecte ou retourne le nom du projet texture
        /// </summary>
        public string Name
        {
            get;
            set;
        }

        /// <summary>
        /// Dernier chemin de sortie
        /// </summary>
        public string FilePath
        {
            get;
            private set;
        }

        /// <summary>
        /// Texture associée aux zones
        /// </summary>
        public Image Texture
        {
            get;
            set;
        }

        /// <summary>
        /// Retourne la liste des frames de la définition
        /// </summary>
        public Dictionary<string, Rectangle> Zones
        {
            get;
            private set;
        }

        #endregion

        #region ICloneable Members

        /// <summary>
        /// Clone l'instance
        /// </summary>
        /// <returns>Clone généré</returns>
        object ICloneable.Clone()
        {
            return (this.Clone());
        }

        /// <summary>
        /// Clone l'instance
        /// </summary>
        /// <returns>Clone généré</returns>
        public virtual Textures Clone()
        {
            Textures oClone = this.MemberwiseClone() as Textures;
            oClone.Texture = this.Texture.Clone() as Image;

            oClone.Zones = new Dictionary<string, Rectangle>();

            foreach ( KeyValuePair<string, Rectangle> oItem in this.Zones )
                oClone.Zones.Add(oItem.Key, new Rectangle(oItem.Value.X, oItem.Value.Y, oItem.Value.Width, oItem.Value.Height));

            return (oClone);
        }

        #endregion
    }
}
